﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using XLETL.Model;
using XLETL.BLL;
using XLETL.ExceptionHandling;
using XLETL.TransformationPluginManager;
using XLETL.Common;
using System.Reflection;

namespace XLETL.TaskManager.Controls
{
    public partial class TransformationPluginsDialog : Form
    {
        PluginStore pluginStore = null;
        Globals.PluginTarget _pluginTarget;
        string targetDbConnString;
        string targetTableName = "";

        public PluginInfo SelectedTransPlugin { get; set; }

        public TransformationPluginsDialog(string dbConnString, string targetTable, PluginInfo pluginToEdit, Globals.PluginTarget pluginTarget)
        {
            InitializeComponent();

            targetDbConnString = dbConnString;
            _pluginTarget = pluginTarget;

            if (targetTable != null)
            {
                targetTableName = targetTable;
            }

            // Load the available plugin list and bind it to the transformation combobox
            if (pluginToEdit == null)
            {
                pluginStore = PluginStoreManager.LoadPuginStore();
                BindPluginsList(false, pluginTarget);
            }
            else // we have the plugin to edit then load only this one
            {
                pluginStore = new PluginStore();
                pluginStore.Plugins.Add(pluginToEdit);
                BindPluginsList(true, pluginTarget);
            }
            
        }

        public delegate void PluginAction(object plugin);

        /// <summary>
        /// Loads the specified plugin
        /// </summary>
        /// <param name="plugin"></param>
        public void DoPluginLoad(object plugin)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new PluginAction(DoPluginLoad), new object[] { plugin });
            }
            else
            {
                Cursor = Cursors.AppStarting;
                SelectedTransPlugin = (PluginInfo)plugin;
                try
                {                    
                  string filePath = System.IO.Path.Combine(GlobalCache.PLUGIN_STORAGE_FOLDER, SelectedTransPlugin.AssemblyFile);
                  Type t = Assembly.LoadFile(filePath).GetType(SelectedTransPlugin.Type);

                    Object[] prms = new Object[2];
                    
                    if (SelectedTransPlugin.PluginParamList != null && SelectedTransPlugin.PluginParamList.Length > 0)
                    {
                        for (int i = 0; i < SelectedTransPlugin.PluginParamList.Length; i++)
                        {
                            // if parameter type equals to DbConnString or DbTableName then assign specific value
                            if (SelectedTransPlugin.PluginParamList[i].ParameterType.Equals(PluginInfo.PARAM_GLOBAL_DB_CONN_STRING))
                            {
                                SelectedTransPlugin.PluginParamList[i].ParameterValue = targetDbConnString;                                
                            }
                            else if (SelectedTransPlugin.PluginParamList[i].ParameterType.Equals(PluginInfo.PARAM_GLOBAL_FOREIGN_TABLE_NAME))
                            {
                                SelectedTransPlugin.PluginParamList[i].ParameterValue = targetTableName;
                            }                            
                        }
                    }

                    // now put the retrieved params into the object array
                    prms[0] = SelectedTransPlugin.PluginParamList;
                    prms[1] = SelectedTransPlugin.TransformationParamList;

                    Control pluginControl = (Control)Activator.CreateInstance(t, prms);

                    this.SuspendLayout();
                    
                    // Remove previous PluginControl if it exists
                    RemovePluginControl();

                    // acquire the size of the selected plugin
                    this.Size = new Size(pluginControl.Size.Width + 30, pluginControl.Size.Height + 130);                    
                    
                    pluginControl.Dock = DockStyle.Fill;
                    pnlPluginViewer.Controls.Add(pluginControl);

                    this.ResumeLayout(true);                    

                }
                catch (Exception e)
                {
                    DisplayPluginLoadError(SelectedTransPlugin, e);
                }

                Cursor = Cursors.Default;
            }
        }

        /// <summary>
        /// Method to remove Plugin control from Plugin Viewer
        /// </summary>
        private void RemovePluginControl()
        {
          if (pnlPluginViewer.Controls.Count > 1)
          {
            Control prevPlugin = pnlPluginViewer.Controls[1];
            pnlPluginViewer.Controls.Remove(prevPlugin);
            prevPlugin.Dispose();
            prevPlugin = null;
          }         
        }

        private void DisplayPluginLoadError(PluginInfo p, Exception e)
        {
            string message = string.Empty;
            if (null != e.InnerException)
                message = e.InnerException.Message;
            else
                message = e.Message;

            MessageBox.Show(this, message, "Plumed!", MessageBoxButtons.OK);            
        }

        private void BindPluginsList(bool isForEditPlugin, Globals.PluginTarget pluginTarget)
        {
            if (!isForEditPlugin)
            {
                cbTransformationPluginList.Items.Add("Select Transformation");
            }

            if (null == pluginStore || pluginStore.Plugins.Count == 0)
            {
                MessageBox.Show("No Transformation plugins found");
            }
            else
            {
              Globals.PluginTarget currentPluginTarget;

              foreach (PluginInfo plugin in pluginStore.Plugins)
              {
                currentPluginTarget = (Globals.PluginTarget)Enum.Parse(typeof(Globals.PluginTarget), plugin.Target, true);

                if (currentPluginTarget == pluginTarget || currentPluginTarget == Globals.PluginTarget.Both)
                {
                  cbTransformationPluginList.Items.Add(plugin);
                }
              }
                
            }

            cbTransformationPluginList.SelectedIndex = 0; // select the first item
        }

        private void cbTransformationPluginList_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (!cbTransformationPluginList.Text.Contains("Select Transformation"))
            {
              label1.Visible = false;
                PluginInfo plugin = cbTransformationPluginList.SelectedItem as PluginInfo;
                if (ThreadPool.QueueUserWorkItem(new WaitCallback(DoPluginLoad), plugin))
                {
                    //SetSatusText("Loading " + plugin.Name + " ...", StatusMessageType.Busy);
                }
                else
                {
                    DoPluginLoad(plugin);
                }
            }
            else
            {
                this.SuspendLayout();
                label1.Visible = true;
                RemovePluginControl();
                this.Size = new Size(290, 251);
                this.ResumeLayout(true);
            }
        }

        private void btnOk_Click(object sender, EventArgs e)
        {
            // make sure any plugin is selected
            if (this.cbTransformationPluginList.SelectedIndex > 0)
            {
                // now get the transformation
                if (this.pnlPluginViewer.Controls.Count > 1 && this.pnlPluginViewer.Controls[1] != null)
                {
                    IPluginControl pluginControl = (IPluginControl)this.pnlPluginViewer.Controls[1];
                    
                    this.SelectedTransPlugin.TransformationParamList = pluginControl.GetTransformationParamList();
                }
            }

            this.DialogResult = DialogResult.OK;
        }

        private void btnCancel_Click(object sender, EventArgs e)
        {
            this.DialogResult = DialogResult.Cancel;
        }
    }
}
